package cz.muni.fi.xvano1.trinity.supplementary;

import cz.muni.fi.xvano1.trinity.data.Event;
import cz.muni.fi.xvano1.trinity.core.Core;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.component.VEvent;

/**
 * This class acts as a supplier for options and data in front end.
 *
 * @author Jan Vano
 */
public class DataSupplier {

    /**
     * Method loads collection events of a specific user in
     * net.fortuna.ical4j.model.component.VEvent format and transform them into
     * list of simpler Events that have getter and setter methods.
     *
     * @param user User whose events are going to be displayed.
     * @return List of events. If the event list is empty or cannot be accessed
     * null is returned.
     */
    public static synchronized List<Event> loadEvents(String user) {
        Core core = new Core(user);
        Calendar calendar = core.load();

        if (calendar == null) {
            return null;
        } else {

            List<Event> eventList = new ArrayList<Event>();
            for (Iterator i = calendar.getComponents().iterator(); i.hasNext();) {
                VEvent event = (VEvent) i.next();
                Event beanEvent = new Event(event);
                eventList.add(beanEvent);
            }
            return eventList;
        }
    }

    /**
     * Method for front end dropbox of reservation types.
     *
     * @return List of types of recurrences.
     */
    public List<Recurrence> getRecurrences() {
        List<Recurrence> response = new ArrayList<Recurrence>();
        response.add(new Recurrence("NONE"));
        response.add(new Recurrence("DAILY"));
        response.add(new Recurrence("WEEKLY"));
        response.add(new Recurrence("MONTHLY"));
        return response;
    }

    /**
     * Method reads configuration file in trinity/data/configuration/ and based
     * on this file, it returns list of administrator.
     *
     * @return List of administrators
     */
    public static synchronized List<String> getAdmins() {
        String path = Core.configDirectory + "config.dat";
        String line;
        List<String> knownAdmins = new ArrayList<String>();
        try {
            BufferedReader r = new BufferedReader(new FileReader(path));
            while ((line = r.readLine()) != null) {
                if (line.matches("administrators=([a-zA-Z0-9]+;)*([a-zA-Z0-9]+)")) {
                    String[] admins = line.substring(15).split(";");
                    knownAdmins.addAll(Arrays.asList(admins));
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(DataSupplier.class.getName()).log(Level.SEVERE, null, ex);
        }
        List<String> response = new ArrayList<String>();
        response.add("admin");

        if (!knownAdmins.isEmpty()) {
            return knownAdmins;
        } else {
            return response;
        }

    }

    /**
     * Method reads configuration file in trinity/data/configuration/ and based
     * on this file, it displays available years for calendar views. If it fails
     * somehow, it returns possibility of years from 2012 to 2014.
     * Administrators should edit this file when new year occurs.
     *
     * @return List of available years
     */
    public List<Integer> getYears() {
        synchronized (getClass()) {
            String path = Core.configDirectory + "config.dat";
            String line;
            List<Integer> availableYears = new ArrayList<Integer>();
            try {
                BufferedReader r = new BufferedReader(new FileReader(path));
                while ((line = r.readLine()) != null) {
                    if (line.matches("years=(\\d\\d\\d\\d;)*(\\d\\d\\d\\d)")) {
                        String[] years = line.substring(6).split(";");
                        for (String year : years) {
                            availableYears.add(Integer.parseInt(year));
                        }
                    }
                }
            } catch (IOException ex) {
                Logger.getLogger(DataSupplier.class.getName()).log(Level.SEVERE, null, ex);
            }
            List<Integer> response = new ArrayList<Integer>();
            response.add(2012);
            response.add(2013);
            response.add(2014);

            if (!availableYears.isEmpty()) {
                return availableYears;
            } else {
                return response;
            }

        }
    }

    /**
     * Static version of getYears method.
     *
     * @return list of years used in application
     */
    public static List<Integer> staticGetYears() {
        return new DataSupplier().getYears();
    }

    /**
     * This method return list of month numbers for drop box in front end.
     *
     * @return List of integers 1 to 12
     */
    public List<Integer> getMonths() {
        List<Integer> response = new ArrayList<Integer>();
        for (int i = 1; i <= 12; i++) {
            response.add(i);
        }
        return response;
    }

    /**
     * Method return list of views for drop box in front end.
     *
     * @return Hardcoded list of views available
     */
    public List<String> getViews() {
        List<String> types = new ArrayList<String>();
        types.add("Yearly");
        types.add("Monthly");
        types.add("Weekly");
        types.add("Daily");
        return types;
    }

    /**
     * Method reads PHP file (locationMap.php) of Lmcal bachelor thesis project
     * (https://is.muni.cz/auth/th/325264/fi_b/). File is based in
     * trinity/lmcal/data/
     *
     * @return List of locations
     */
    public List<String> getLocations() {
        synchronized (getClass()) {
            List<String> locations = new ArrayList<String>();
            String path = Core.lmcal + "data/locationMap.php";
            String line;
            try {
                BufferedReader r = new BufferedReader(new FileReader(path));
                while ((line = r.readLine()) != null) {
                    if (line.matches("( )*\"([a-zA-Z0-9 _])+\" => \"(.)+\"(,)?")) {
                        String location = line.split("\"")[1];
                        locations.add(location);
                    }
                }
            } catch (IOException ex) {
                Logger.getLogger(DataSupplier.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ArrayIndexOutOfBoundsException ex) {
                Logger.getLogger(DataSupplier.class.getName()).log(Level.SEVERE, null, ex);
            }
            return locations;
        }
    }

    /**
     * Static version of getLocations() method.
     *
     * @return List of locations
     */
    public static List<String> staticGetLocations() {
        return new DataSupplier().getLocations();
    }

    public static List<String> getUsers() {
        String path = Core.userDirectory;
        List<String> users = new ArrayList<String>();
        String file;
        File folder = new File(path);
        File[] listOfFiles = folder.listFiles();
        for (int i = 0; i < listOfFiles.length; i++) {
            if (listOfFiles[i].isFile()) {
                file = listOfFiles[i].getName();
                if (file.endsWith(".ics")) {
                    if (!file.contains("_tmp")) {
                        users.add(file.split("\\.ics")[0]);
                    }
                }
            }
        }
        return users;
    }
}